Add Windows 7 release target - #11
Conversation
- we are not exposing any public functions, hence doctests will fail otherwise
WalkthroughDocumentation expanded across many modules; keyword normalization added; attachment duplicate-name detection implemented; release workflow matrix extended with per-target toolchain settings, conditional rust-src/install-target steps, and SAFE_REF-driven dynamic packaging. No public API signatures changed. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/mvu/mod.rs (1)
337-347: Consider surfacing a specific message for invalid email fields.In
validate_for_save, URL, number, and integer errors get tailored user messages, while the"invalid_email"case falls through to the generic"Field '{label}' is invalid.". For consistency and clearer feedback, I recommend adding an explicit branch for"invalid_email"(and corresponding tests alongside the URL/number/integer cases).Also applies to: 483-507
🧹 Nitpick comments (5)
src/ui/components/extra_fields.rs (2)
45-56: Extra‑fields UI helpers are now well-documented and easier to reason about.The new Rustdoc on
ExtraFieldsModelaccessors, helpers likesplit_multi,name_conflict,apply_draft_to_field, and the test utilities significantly clarifies the MVU flow and invariants while keeping UI code side‑effect free. Usingrust,ignorefor sketch-like examples is appropriate here. Nicely done.Also applies to: 78-84, 95-101, 137-142, 162-171, 187-201, 318-323, 389-397, 415-423, 443-451, 463-471, 487-502, 607-615, 1210-1213, 1229-1236, 1255-1258, 1267-1271, 1288-1325, 1534-1543, 1567-1573, 1735-1753, 1765-1788, 1868-1877
1365-1421: render_field_modal’s early‑return guard is a sensible defensive improvement.The
let Some(draft) = model.modal_draft.clone() else { return; };guard ensures the modal is only rendered when a draft actually exists, preventing any chance of inconsistent state or panics ifmodal_openis ever true without a draft. The cloneddraftis used read‑only for this frame, and all mutations still flow through messages, preserving the MVU contract. This is a clean, Picard‑approved refinement.Also applies to: 1497-1522
src/models/attachment.rs (2)
27-46: Clarifysanitized_nameprecondition and link to the validator.This documentation is strong and sets the right expectations. To be perfectly clear: uniqueness is a precondition here, not enforced by the constructor itself. I recommend explicitly pointing callers to
assert_unique_sanitized_namesas the companion invariant check.For example:
-/// The caller must provide a name that is already filesystem-safe and -/// unique within the archive. +/// The caller must provide a name that is already filesystem-safe and +/// unique within the archive. +/// +/// Use [`assert_unique_sanitized_names`] when assembling an archive to +/// validate that this uniqueness invariant holds.This keeps the model aligned with the Attachments UI’s sanitize/dedupe behavior. Based on learnings, this will make the data flow more obvious between
src/models/attachment.rsand the attachments panel.
64-93: Duplicate-name detection is correct; review callers and consider avoiding the extra clone.The HashSet-based duplicate check behaves as advertised: the first occurrence is accepted, subsequent identical
sanitized_namevalues correctly trigger an error with a clear message. This is a welcome tightening of invariants.Two follow-ups I recommend:
- Call-site behavior. Previously this function always returned
Ok(()); now duplicates surface asErr. Please review the call sites (in particular anything feeding the Attachments UI or archive creation) to ensure they handle this error path appropriately—e.g., mapping it to a user-visible warning rather than an unexpected panic. Based on learnings, that keeps the Attachments panel’s warning story coherent.- Optional micro-optimization. To avoid allocating cloned
Strings solely for set membership, you could store&strin the set:-pub fn assert_unique_sanitized_names(attachments: &[Attachment]) -> Result<()> { - let mut seen = HashSet::new(); - for att in attachments { - if !seen.insert(att.sanitized_name.clone()) { +pub fn assert_unique_sanitized_names(attachments: &[Attachment]) -> Result<()> { + let mut seen: HashSet<&str> = HashSet::new(); + for att in attachments { + if !seen.insert(&att.sanitized_name) { return Err(anyhow!( "Duplicate attachment filename in archive: {}", att.sanitized_name )); } } Ok(()) }The existing implementation is entirely acceptable; this adjustment is merely a refinement.
src/models/keywords.rs (1)
58-70: Optional: use a set for normalization to simplify intent and scale better.The current
normalizeimplementation is correct and matches the documented behavior, but it performs anO(n²)scan viaseen.containson aVec<String>. If keyword lists grow, you could simplify the logic and improve scaling with aHashSet:-use super::*; +use std::collections::HashSet; + fn normalize(&mut self) { - // Dedup case-insensitively while preserving original casing of first occurrence. - let mut seen = Vec::<String>::new(); - self.items.retain(|kw| { - let lower = kw.to_ascii_lowercase(); - if seen.contains(&lower) { - false - } else { - seen.push(lower); - true - } - }); + // Dedup case-insensitively while preserving original casing of first occurrence. + let mut seen = HashSet::new(); + self.items.retain(|kw| seen.insert(kw.to_ascii_lowercase())); }Functionally identical, but slightly clearer in its intent. The existing approach is acceptable if keyword counts are expected to remain small; treat this as a refinement to consider rather than a requirement.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.github/workflows/release.yml(1 hunks)src/app/mod.rs(1 hunks)src/logic/eln.rs(4 hunks)src/models/attachment.rs(2 hunks)src/models/extra_fields.rs(4 hunks)src/models/keywords.rs(2 hunks)src/mvu/mod.rs(3 hunks)src/ui/components/extra_fields.rs(28 hunks)src/ui/mod.rs(0 hunks)src/utils/hash.rs(1 hunks)src/utils/sanitize_component.rs(1 hunks)
💤 Files with no reviewable changes (1)
- src/ui/mod.rs
🧰 Additional context used
📓 Path-based instructions (8)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Rust 2024 crate; entry point atsrc/main.rs, which callsapp::run()to start eframe/egui. SPDX headers on sources:SPDX-License-Identifier: MITplus one or moreSPDX-FileCopyrightTextlines naming actual authors.
Use///for public items and//!for module-level docs in Rustdoc; start with a one-line summary ending with a period.
Structure Rustdoc details with#headings (e.g.,# Examples,# Errors,# Panics,# Safety,# Performance); include small runnable examples markedno_run/ignorewhen side effects exist.
Explain invariants, panics, and error cases explicitly in Rustdoc; prefer present tense and describe behavior, not intent.
Link related items in Rustdoc with intra-doc links like[TypeName]or[module::function]; disambiguate with full paths when needed.
Follow rustfmt defaults (4-space indent, trailing commas where appropriate); runcargo fmtbefore committing.
Prefersnake_casefor functions/variables/files andCamelCasefor types; keep module files small and focused.
Code comments: use sparingly to explain intent, invariants, or non-obvious control flow; avoid restating what the code already makes clear.
Name tests after behavior (e.g.,submits_trimmed_input) and keep them deterministic.
Files:
src/app/mod.rssrc/models/extra_fields.rssrc/logic/eln.rssrc/mvu/mod.rssrc/utils/sanitize_component.rssrc/utils/hash.rssrc/ui/components/extra_fields.rssrc/models/keywords.rssrc/models/attachment.rs
src/app/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/app/handles eframe bootstrap and font/theme setup.
Files:
src/app/mod.rs
src/models/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/models/contains pure data/validation (attachment,keywords).
Files:
src/models/extra_fields.rssrc/models/keywords.rssrc/models/attachment.rs
src/logic/eln.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/logic/eln.rs:src/logic/eln.rshandles ELN RO-Crate build/write, metadata, suggested archive name. Conform to RO-Crate 1.2 and ELN File Format spec; use pre-sanitized names from attachments. No UI deps. Extra fields export: archives emit eLabFTW-style PropertyValue nodes with metadata blob.
For archive structure and metadata, align with the ELN File Format specification: https://raw.githubusercontent.com/TheELNConsortium/TheELNFileFormat/refs/heads/master/SPECIFICATION.md
Files:
src/logic/eln.rs
src/mvu/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Update layer should route messages in
mvu::update, validate save requests, and enqueueCommands inrun_command.
Files:
src/mvu/mod.rs
src/utils/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/utils/contains helpers (sanitize_component,hash_file).
Files:
src/utils/sanitize_component.rssrc/utils/hash.rs
src/ui/components/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
View components should implement
view(...) -> Vec<Msg>inui/components/*;ui::ElnPackAppcomposes and wraps intomvu::Msg.
Files:
src/ui/components/extra_fields.rs
src/ui/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/ui/**/*.rs: UI components insrc/ui/andsrc/ui/components/*stay side-effect free; they emit messages only.
Phosphor icons: the font is registered insrc/main.rs; useegui_phosphor::regular::NAME(viaRichTextor button labels) instead of embedding SVGs. Keep icon+text buttons short and reuse helpers already insrc/ui.rs.
src/ui/handles UI composition and screens; collects component messages and feeds them intomvu::update/run_command. Save flow: opens file dialog, dispatchesMsg::SaveRequested; kernel validates.
File dialog operations userfdcrate for cross-platform native dialogs.
Files:
src/ui/components/extra_fields.rs
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Pull requests should describe the change, note any UI updates, and link related issues. Include screenshots or short screen recordings when modifying UI behavior.
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Keep commits scoped and reviewable; avoid bundling formatting-only changes with behavior changes.
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Structure Rustdoc details with `#` headings (e.g., `# Examples`, `# Errors`, `# Panics`, `# Safety`, `# Performance`); include small runnable examples marked `no_run`/`ignore` when side effects exist.
Applied to files:
src/app/mod.rssrc/models/extra_fields.rssrc/logic/eln.rssrc/mvu/mod.rssrc/utils/sanitize_component.rssrc/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/main.rs : `src/main.rs` is the entry point; loads modules and calls `app::run()`.
Applied to files:
src/app/mod.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Use `///` for public items and `//!` for module-level docs in Rustdoc; start with a one-line summary ending with a period.
Applied to files:
src/app/mod.rssrc/models/extra_fields.rssrc/logic/eln.rssrc/mvu/mod.rssrc/ui/components/extra_fields.rssrc/models/keywords.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Explain invariants, panics, and error cases explicitly in Rustdoc; prefer present tense and describe behavior, not intent.
Applied to files:
src/app/mod.rssrc/models/extra_fields.rssrc/logic/eln.rssrc/mvu/mod.rssrc/utils/sanitize_component.rssrc/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Rust 2024 crate; entry point at `src/main.rs`, which calls `app::run()` to start eframe/egui. SPDX headers on sources: `SPDX-License-Identifier: MIT` plus one or more `SPDX-FileCopyrightText` lines naming actual authors.
Applied to files:
src/app/mod.rssrc/models/extra_fields.rssrc/logic/eln.rssrc/mvu/mod.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Code comments: use sparingly to explain intent, invariants, or non-obvious control flow; avoid restating what the code already makes clear.
Applied to files:
src/models/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/logic/eln.rs : For archive structure and metadata, align with the ELN File Format specification: https://raw.githubusercontent.com/TheELNConsortium/TheELNFileFormat/refs/heads/master/SPECIFICATION.md
Applied to files:
src/models/extra_fields.rssrc/logic/eln.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Link related items in Rustdoc with intra-doc links like `[TypeName]` or `[module::function]`; disambiguate with full paths when needed.
Applied to files:
src/models/extra_fields.rssrc/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Test business logic in `src/logic/eln.rs` independently of UI; mock file system operations where appropriate.
Applied to files:
src/logic/eln.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/logic/eln.rs : `src/logic/eln.rs` handles ELN RO-Crate build/write, metadata, suggested archive name. Conform to RO-Crate 1.2 and ELN File Format spec; use pre-sanitized names from attachments. No UI deps. Extra fields export: archives emit eLabFTW-style PropertyValue nodes with metadata blob.
Applied to files:
src/logic/eln.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Separate UI concerns (`src/ui.rs`) from business logic (`src/logic/eln.rs`) for maintainability and testability.
Applied to files:
src/logic/eln.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Separate data models in `src/models/`; business/format logic in `src/logic/eln.rs`; MVU kernel in `src/mvu/`; UI composition in `src/ui/`; components in `src/ui/components/`; utilities in `src/utils/`.
Applied to files:
src/logic/eln.rssrc/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/components/datetime_picker.rs : `src/ui/components/datetime_picker.rs` implements a Date/time picker; converts to `OffsetDateTime`.
Applied to files:
src/logic/eln.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to **/*.rs : Follow rustfmt defaults (4-space indent, trailing commas where appropriate); run `cargo fmt` before committing.
Applied to files:
src/mvu/mod.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/mvu/**/*.rs : Update layer should route messages in `mvu::update`, validate save requests, and enqueue `Command`s in `run_command`.
Applied to files:
src/mvu/mod.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Commands (`PickFiles`, `HashFile`, `LoadThumbnail`, `SaveArchive`) results feed back as messages; flow: UI event → component `Msg` → `mvu::update` mutates model/enqueues commands → `run_command` performs IO → resulting `Msg` goes back into `update`.
Applied to files:
src/mvu/mod.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/components/attachments.rs : `src/ui/components/attachments.rs` implements an Attachments panel (list, thumbnails, inline filename editing). Compute `sanitized_name` using `sanitize_component`; show WARNING icon on sanitized mismatch; emit commands for file picking/hashing/thumbnails; edited names are sanitized/deduped.
Applied to files:
src/utils/sanitize_component.rssrc/models/attachment.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/utils/**/*.rs : `src/utils/` contains helpers (`sanitize_component`, `hash_file`).
Applied to files:
src/utils/sanitize_component.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/components/markdown.rs : `src/ui/components/markdown.rs` implements a Markdown editor (toolbar, cursor-aware insertions, text area).
Applied to files:
src/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/components/keywords.rs : `src/ui/components/keywords.rs` implements a Keywords editor with inline edits and add-keywords modal.
Applied to files:
src/ui/components/extra_fields.rssrc/models/keywords.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui.rs : UI strings live directly in `src/ui.rs` within the egui code; prefer short, actionable labels.
Applied to files:
src/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/**/*.rs : UI components in `src/ui/` and `src/ui/components/*` stay side-effect free; they emit messages only.
Applied to files:
src/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/components/**/*.rs : View components should implement `view(...) -> Vec<Msg>` in `ui/components/*`; `ui::ElnPackApp` composes and wraps into `mvu::Msg`.
Applied to files:
src/ui/components/extra_fields.rs
📚 Learning: 2025-12-03T09:56:40.111Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T09:56:40.111Z
Learning: Applies to src/ui/**/*.rs : `src/ui/` handles UI composition and screens; collects component messages and feeds them into `mvu::update`/`run_command`. Save flow: opens file dialog, dispatches `Msg::SaveRequested`; kernel validates.
Applied to files:
src/ui/components/extra_fields.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (rust)
🔇 Additional comments (9)
src/models/extra_fields.rs (1)
41-47: Rustdoc examples now match behavior and house style.These
rust,ignoreexamples correctly describe the current behavior ofExtraFieldKind::from_str,validate_field,parse_elabftw_extra_fields, andvalue_to_string, and they follow the Rustdoc structure from the guidelines. No further changes requested.Also applies to: 131-155, 283-297, 389-397
src/utils/hash.rs (1)
13-25: hash_file documentation is clear and precise.The expanded description,
# Errors, and example accurately describe the existing behavior (lowercase SHA‑256 hex, I/O failures via anyhow). This is a solid improvement with no behavioral changes.src/app/mod.rs (1)
11-22: run() Rustdoc matches actual behavior and entry-point contract.The new summary,
# Errors, and example reflect howrun()boots the egui event loop and surfaceseframe::run_nativefailures, in line with the documented main entry flow. No changes needed—carry on.src/mvu/mod.rs (1)
117-124: MVU docs now better scoped as non-executable examples.Converting these examples to
rust,ignorekeeps them illustrative without forcing full scaffolding, and they accurately describeupdate,run_command, and the test helper behavior. This aligns well with the documented MVU flow.Also applies to: 221-233, 607-614
src/utils/sanitize_component.rs (1)
17-25: sanitize_component behavior is now well-documented and thoroughly exercised.The stepwise description and examples line up with the existing implementation, and the new tests cover the critical edge cases (transliteration, run collapsing, Windows reserved basenames, dot-only names). A tidy piece of work—no changes requested.
Also applies to: 125-165
src/logic/eln.rs (1)
97-122: RO‑Crate/extra‑fields docs remain accurate with safer doc tests.Marking these illustrative snippets as
rust,ignoreavoids brittle doctests while preserving clear guidance on archive construction, extra-field export, and value serialization. The behavior and ELN/RO‑Crate responsibilities remain correctly described.Also applies to: 318-322, 396-400, 525-547
src/models/keywords.rs (3)
13-30: Docs and construction behavior are aligned; semantics are well captured.The updated Rustdoc accurately reflects the normalization behavior—case-insensitive deduplication, first-occurrence casing preserved, and whitespace left intact—and the example makes that contract explicit. Combined with the
normalizecall innew, this neatly centralizes keyword hygiene for the rest of the codebase, which will serve the Keywords UI well.
32-41:itemsaccessor docs are precise and match behavior.The documentation clearly conveys that callers receive a borrowed, already-normalized slice, and the example demonstrates typical usage succinctly. The implementation itself is straightforward and correct.
45-53:into_vecdocumentation cleanly explains ownership transfer.The example and one-line summary make it unambiguous that this consumes the wrapper and yields the normalized keywords by value. This is exactly the clarity one wants at the model layer.
Summary
win7-windows-msvcrelease targetsTesting
cargo fmtcargo clippy --all-targets --all-featurescargo testNotes for reviewers
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.